//  h6280.c - Execute CPU instructions
//

#include <stdio.h>
#include <stdlib.h>

#include "interupt.h"
#include "dis_runtime.h"
#include "pce.h"
#include "hard_pce.h"
#include "gfx.h"
#include "pce.h"
#include "utils.h"

#if defined(KERNEL_DEBUG)
static
int one_bit_set(UChar arg)
{
  return (arg != 0) && ((-arg & arg) == arg);
}
#endif

// flag-value table (for speed)

UChar flnz_list[256] = {
  FL_Z,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,       // 00-0F
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          // 40-4F
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          // 70-7F
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,  // 80-87
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,  // 90-97
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,  // A0-A7
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,  // B0-B7
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,  // C0-C7
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,  // D0-D7
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,  // E0-E7
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,  // F0-F7
  FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N,FL_N
};

// Elementary operations:
// - defined here for clarity, brevity,
//   and reduced typographical errors

// This code ignores hardware-segment accesses; it should only be used
// to access immediate data (hardware segment does not run code):
//
//  as a function:

inline UChar imm_operand(UInt16 addr) {
  register unsigned short int memreg = addr>>13;
  return( (UChar) (PageR[memreg][addr]));
}

static inline UChar simm_operand(UInt16 addr) {
//  register unsigned short int memreg = addr>>13;
  return( (UChar) (PageR[addr>>13][addr]));
}

#if !defined(INLINED_ACCESSORS)

#define get_8bit_addr(addr) Rd6502((addr))

#define put_8bit_addr(addr,byte) Wr6502((addr),(byte))

#define get_16bit_addr(addr) (Rd6502(addr) + (Rd6502((UInt16)(addr + 1)) << 8))

#else


// This is the more generalized access routine:
inline UChar get_8bit_addr(UInt16 addr) {
  register unsigned short int memreg = addr>>13;

  if (PageR[memreg] == IOAREA)
    return(IO_read(addr));
  else
    return((UChar) (PageR[memreg][addr]));
}

inline void put_8bit_addr(UInt16 addr, UChar byte) {
  register unsigned int memreg = addr>>13;

  if (PageW[memreg] == IOAREA) {
    IO_write(addr, byte);
  } else {
    PageW[memreg][addr] = byte;
  }
}

inline UInt16 get_16bit_addr(UInt16 addr) {
  register unsigned int memreg = addr>>13;
  UInt16 ret_16bit = (UChar) PageR[memreg][addr];
  memreg = (++addr)>>13;
  ret_16bit += (UInt16) ((UChar) PageR[memreg][addr] << 8);

  return(ret_16bit);
}

#endif

//Addressing modes:

#define abs_operand(x)     get_8bit_addr(get_16bit_addr(x))
#define absx_operand(x)    get_8bit_addr(get_16bit_addr(x)+reg_x)
#define absy_operand(x)    get_8bit_addr(get_16bit_addr(x)+reg_y)
#define zp_operand(x)      get_8bit_zp(simm_operand(x))
#define zpx_operand(x)     get_8bit_zp(simm_operand(x)+reg_x)
#define zpy_operand(x)     get_8bit_zp(simm_operand(x)+reg_y)
#define zpind_operand(x)   get_8bit_addr(get_16bit_zp(simm_operand(x)))
#define zpindx_operand(x)  get_8bit_addr(get_16bit_zp(simm_operand(x)+reg_x))
#define zpindy_operand(x)  get_8bit_addr(get_16bit_zp(simm_operand(x))+reg_y)

// Elementary flag check (flags 'N' and 'Z'):

#define chk_flnz_8bit(x) reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[x]);

inline UChar get_8bit_zp(UChar zp_addr) {
  return((UChar) *(zp_base + zp_addr) );
}

inline UInt16 get_16bit_zp(UChar zp_addr) {
  UInt16 n = *(zp_base + zp_addr);
  n += (*(zp_base + (UChar)(zp_addr+1)) << 8);
  return(n);
}

inline void put_8bit_zp(UChar zp_addr, UChar byte) {
  *(zp_base + zp_addr) = byte;
}

inline void push_8bit(UChar byte) {
  *(sp_base + reg_s--) = byte;
}

inline UChar pull_8bit(void) {
  return((UChar) *(sp_base + ++reg_s) );
}

inline void push_16bit(UInt16 addr) {
  *(sp_base + reg_s--) = (UChar)(addr>>8);
  *(sp_base + reg_s--) = (UChar)(addr&0xFF);
  return;
}

inline UInt16 pull_16bit(void) {
  UInt16 n = (UChar) *(sp_base + ++reg_s);
  n += (UInt16)(((UChar) *(sp_base + ++reg_s)) << 8);
  return(n);
}

//
// Implementation of actual opcodes:
//

/*@ -type */

static
UChar adc(UChar acc, UChar val) {
  Int16  sig  = (Char)acc;
  UInt16 usig = (UChar)acc;
  UInt16 temp;

  if (!(reg_p & FL_D)) {		/* binary mode */
    if (reg_p & FL_C) {
      usig++;
      sig++;
    }
    sig  += (Char)val;
    usig += (UChar)val;
    acc   = (UChar)(usig & 0xFF);

    reg_p = (reg_p & ~(FL_N|FL_V|FL_T|FL_Z|FL_C))
            | (((sig > 127) || (sig < -128)) ? FL_V:0)
            | ((usig > 255) ? FL_C:0)
            | flnz_list[acc];

  } else {				/* decimal mode */

// treatment of out-of-range accumulator
// and operand values (non-BCD) is not
// adequately defined.	Nor is overflow
// flag treatment.

// Zeo : rewrote using bcdbin and binbcd arrays to boost code speed and fix
// residual bugs

    temp  = bcdbin[usig] + bcdbin[val];

    if (reg_p & FL_C) { temp++; }

    acc    = binbcd[temp];

    reg_p  = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	     | ((temp > 99) ? FL_C:0)
	     | flnz_list[acc];

    cycles++;	/* decimal mode takes an extra cycle */

  }
  return(acc);
}

static
void sbc(UChar val) {
  Int16  sig  = (Char)reg_a;
  UInt16 usig = (UChar)reg_a;
  Int16  temp;

  if (!(reg_p & FL_D)) {		/* binary mode */
    if (!(reg_p & FL_C)) {
      usig--;
      sig--;
    }
    sig   -= (Char)val;
    usig  -= (UChar)val;
    reg_a  = (UChar)(usig & 0xFF);
    reg_p  = (reg_p & ~(FL_N|FL_V|FL_T|FL_Z|FL_C))
	     | (((sig > 127) || (sig < -128)) ? FL_V:0)
	     | ((usig > 255) ? 0:FL_C)
	     | flnz_list[reg_a];      /* FL_N, FL_Z */

  } else {				/* decimal mode */

// treatment of out-of-range accumulator
// and operand values (non-bcd) is not
// adequately defined.	Nor is overflow
// flag treatment.

    temp  = (Int16)(bcdbin[usig] - bcdbin[val]);

    if (!(reg_p & FL_C)) { temp--; }

    reg_p  = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	     | ((temp < 0) ? 0:FL_C);

    while (temp < 0) {
      temp += 100;
    }

    chk_flnz_8bit(reg_a = binbcd[temp]);

    cycles++;	/* decimal mode takes an extra cycle */

  }
}

void adc_abs(void) {
// if flag 'T' is set, use zero-page address specified by register 'X'
// as the accumulator...

  if (reg_p & FL_T) {
    put_8bit_zp(reg_x, adc(get_8bit_zp(reg_x), abs_operand(reg_pc+1)));
    cycles+=8;
  } else {
    reg_a = adc(reg_a, abs_operand(reg_pc+1));
    cycles+=5;
  }
  reg_pc+=3;
//  return 0;
}

void adc_absx(void) {
  if (reg_p & FL_T) {
    put_8bit_zp(reg_x, adc(get_8bit_zp(reg_x), absx_operand(reg_pc+1)));
    cycles+=8;
  } else {
    reg_a = adc(reg_a, absx_operand(reg_pc+1));
    cycles+=5;
  }
  reg_pc+=3;
//  return 0;
}

void adc_absy(void) {
  if (reg_p & FL_T) {
    put_8bit_zp(reg_x, adc(get_8bit_zp(reg_x), absy_operand(reg_pc+1)));
    cycles+=8;
  } else {
    reg_a = adc(reg_a, absy_operand(reg_pc+1));
    cycles+=5;
  }
  reg_pc+=3;
//  return 0;
}

void adc_imm(void) {
  if (reg_p & FL_T) {
    put_8bit_zp(reg_x, adc(get_8bit_zp(reg_x), simm_operand(reg_pc+1)));
    cycles+=5;
  } else {
    reg_a = adc(reg_a, simm_operand(reg_pc+1));
    cycles+=2;
  }
  reg_pc+=2;
//  return 0;
}

void adc_zp(void) {
  if (reg_p & FL_T) {
    put_8bit_zp(reg_x, adc(get_8bit_zp(reg_x), zp_operand(reg_pc+1)));
    cycles+=7;
  } else {
    reg_a = adc(reg_a, zp_operand(reg_pc+1));
    cycles+=4;
  }
  reg_pc+=2;
//  return 0;
}

void adc_zpx(void) {
  if (reg_p & FL_T) {
    put_8bit_zp(reg_x, adc(get_8bit_zp(reg_x), zpx_operand(reg_pc+1)));
    cycles+=7;
  } else {
    reg_a = adc(reg_a, zpx_operand(reg_pc+1));
    cycles+=4;
  }
  reg_pc+=2;
//  return 0;
}

void adc_zpind(void) {
  if (reg_p & FL_T) {
    put_8bit_zp(reg_x, adc(get_8bit_zp(reg_x), zpind_operand(reg_pc+1)));
    cycles+=10;
  } else {
    reg_a = adc(reg_a, zpind_operand(reg_pc+1));
    cycles+=7;
  }
  reg_pc+=2;
//  return 0;
}

void adc_zpindx(void) {
  if (reg_p & FL_T) {
    put_8bit_zp(reg_x, adc(get_8bit_zp(reg_x), zpindx_operand(reg_pc+1)));
    cycles+=10;
  } else {
    reg_a = adc(reg_a, zpindx_operand(reg_pc+1));
    cycles+=7;
  }
  reg_pc+=2;
//  return 0;
}

void adc_zpindy(void) {
  if (reg_p & FL_T) {
    put_8bit_zp(reg_x, adc(get_8bit_zp(reg_x), zpindy_operand(reg_pc+1)));
    cycles+=10;
  } else {
    reg_a = adc(reg_a, zpindy_operand(reg_pc+1));
    cycles+=7;
  }
  reg_pc+=2;
//  return 0;
}

void and_abs(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp &= abs_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=8;

  } else {
    chk_flnz_8bit(reg_a &= abs_operand(reg_pc+1));
    cycles+=5;
  }
  reg_pc+=3;
//  return 0;
}

void and_absx(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp &= absx_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=8;

  } else {
    chk_flnz_8bit(reg_a &= absx_operand(reg_pc+1));
    cycles+=5;
  }
  reg_pc+=3;
//  return 0;
}

void and_absy(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp &= absy_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=8;

  } else {
    chk_flnz_8bit(reg_a &= absy_operand(reg_pc+1));
    cycles+=5;
  }
  reg_pc+=3;
//  return 0;
}

void and_imm(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp &= simm_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=5;

  } else {
    chk_flnz_8bit(reg_a &= simm_operand(reg_pc+1));
    cycles+=2;
  }
  reg_pc+=2;
//  return 0;
}

void and_zp(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp &= zp_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=7;

  } else {
    chk_flnz_8bit(reg_a &= zp_operand(reg_pc+1));
    cycles+=4;
  }
  reg_pc+=2;
//  return 0;
}

void and_zpx(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp &= zpx_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=7;

  } else {
    chk_flnz_8bit(reg_a &= zpx_operand(reg_pc+1));
    cycles+=4;
  }
  reg_pc+=2;
//  return 0;
}

void and_zpind(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp &= zpind_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=10;

  } else {
    chk_flnz_8bit(reg_a &= zpind_operand(reg_pc+1));
    cycles+=7;
  }
  reg_pc+=2;
//  return 0;
}

void and_zpindx(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp &= zpindx_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=10;

  } else {
    chk_flnz_8bit(reg_a &= zpindx_operand(reg_pc+1));
    cycles+=7;
  }
  reg_pc+=2;
//  return 0;
}

void and_zpindy(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp &= zpindy_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=10;

  } else {
    chk_flnz_8bit(reg_a &= zpindy_operand(reg_pc+1));
    cycles+=7;
  }
  reg_pc+=2;
//  return 0;
}

void asl_a(void) {
  UChar temp1 = reg_a;
  reg_a<<=1;
  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1 & 0x80) ? FL_C:0)
	  | flnz_list[reg_a];
  cycles+=2;
  reg_pc++;
//  return 0;
}

void asl_abs(void) {
  UInt16 temp_addr = get_16bit_addr(reg_pc+1);
  UChar  temp1	   = get_8bit_addr(temp_addr);
  UChar  temp	   = temp1<<1;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1 & 0x80) ? FL_C:0)
	  | flnz_list[temp];
  cycles+=7;

  put_8bit_addr(temp_addr,temp);
  reg_pc+=3;
//  return 0;
}

void asl_absx(void) {
  UInt16 temp_addr = get_16bit_addr(reg_pc+1)+reg_x;
  UChar  temp1	   = get_8bit_addr(temp_addr);
  UChar  temp	   = temp1<<1;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1 & 0x80) ? FL_C:0)
	  | flnz_list[temp];
  cycles+=7;
  put_8bit_addr(temp_addr,temp);
  reg_pc+=3;
//  return 0;
}

void asl_zp(void) {
  UChar zp_addr = simm_operand(reg_pc+1);
  UChar temp1	= get_8bit_zp(zp_addr);
  UChar temp	= temp1<<1;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1 & 0x80) ? FL_C:0)
	  | flnz_list[temp];
  cycles+=6;
  put_8bit_zp(zp_addr, temp);
  reg_pc+=2;
//  return 0;
}

void asl_zpx(void) {
  UChar  zp_addr = simm_operand(reg_pc+1)+reg_x;
  UChar  temp1	 = get_8bit_zp(zp_addr);
  UChar  temp	 = temp1<<1;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1 & 0x80) ? FL_C:0)
	  | flnz_list[temp];
  cycles+=6;
  put_8bit_zp(zp_addr, temp);
  reg_pc+=2;
//  return 0;
}

void bbr0(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x01) {
    reg_pc+=3;
    cycles+=6;
  } else {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  }
//  return 0;
}

void bbr1(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x02) {
    reg_pc+=3;
    cycles+=6;
  } else {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  }
//  return 0;
}

void bbr2(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x04) {
    reg_pc+=3;
    cycles+=6;
  } else {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  }
////  return 0;
}

void bbr3(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x08) {
    reg_pc+=3;
    cycles+=6;
  } else {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  }
////  return 0;
}

void bbr4(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x10) {
    reg_pc+=3;
    cycles+=6;
  } else {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  }
////  return 0;
}

void bbr5(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x20) {
    reg_pc+=3;
    cycles+=6;
  } else {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  }
////  return 0;
}

void bbr6(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x40) {
    reg_pc+=3;
    cycles+=6;
  } else {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  }
////  return 0;
}

void bbr7(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x80) {
    reg_pc+=3;
    cycles+=6;
  } else {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  }
//  return 0;
}

void bbs0(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x01) {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  } else {
    reg_pc+=3;
    cycles+=6;
  }
//  return 0;
}

void bbs1(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x02) {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  } else {
    reg_pc+=3;
    cycles+=6;
  }
//  return 0;
}

void bbs2(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x04) {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  } else {
    reg_pc+=3;
    cycles+=6;
  }
//  return 0;
}

void bbs3(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x08) {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  } else {
    reg_pc+=3;
    cycles+=6;
  }
//  return 0;
}

void bbs4(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x10) {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  } else {
    reg_pc+=3;
    cycles+=6;
  }
//  return 0;
}

void bbs5(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x20) {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  } else {
    reg_pc+=3;
    cycles+=6;
  }
//  return 0;
}

void bbs6(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x40) {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  } else {
    reg_pc+=3;
    cycles+=6;
  }
//  return 0;
}

void bbs7(void) {
  reg_p &= ~FL_T;
  if (zp_operand(reg_pc+1)&0x80) {
    reg_pc+=(Char)simm_operand(reg_pc+2)+3;
    cycles+=8;
  } else {
    reg_pc+=3;
    cycles+=6;
  }
//  return 0;
}

void bcc(void) {
  reg_p &= ~FL_T;
  if (reg_p & FL_C) {
    reg_pc+=2;
    cycles+=2;
  } else {
    reg_pc+=(Char)simm_operand(reg_pc+1)+2;
    cycles+=4;
  }
//  return 0;
}

void bcs(void) {
  reg_p &= ~FL_T;
  if (reg_p & FL_C) {
    reg_pc+=(Char)simm_operand(reg_pc+1)+2;
    cycles+=4;
  } else {
    reg_pc+=2;
    cycles+=2;
  }
//  return 0;
}

void beq(void) {
  reg_p &= ~FL_T;
  if (reg_p & FL_Z) {
    reg_pc+=(Char)simm_operand(reg_pc+1)+2;
    cycles+=4;
  } else {
    reg_pc+=2;
    cycles+=2;
  }
//  return 0;
}

void bit_abs(void) {
  UChar temp = abs_operand(reg_pc+1);
  reg_p = (reg_p & ~(FL_N|FL_V|FL_T|FL_Z))
	  | ((temp&0x80)  ? FL_N:0)
	  | ((temp&0x40)  ? FL_V:0)
	  | ((reg_a&temp) ? 0:FL_Z);
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void bit_absx(void) {
  UChar temp = absx_operand(reg_pc+1);
  reg_p = (reg_p & ~(FL_N|FL_V|FL_T|FL_Z))
	  | ((temp&0x80)  ? FL_N:0)
	  | ((temp&0x40)  ? FL_V:0)
	  | ((reg_a&temp) ? 0:FL_Z);
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void bit_imm(void) {
// orig code (Eyes/Lichty said immediate mode did not affect
//            'N' and 'V' flags):
//reg_p = (reg_p & ~(FL_T|FL_Z))
//	  | ((reg_a & simm_operand(reg_pc+1)) ? 0:FL_Z);

  UChar temp = simm_operand(reg_pc+1);
  reg_p = (reg_p & ~(FL_N|FL_V|FL_T|FL_Z))
	  | ((temp&0x80)  ? FL_N:0)
	  | ((temp&0x40)  ? FL_V:0)
	  | ((reg_a&temp) ? 0:FL_Z);
  reg_pc+=2;
  cycles+=2;
//  return 0;
}

void bit_zp(void) {
  UChar temp = zp_operand(reg_pc+1);
  reg_p = (reg_p & ~(FL_N|FL_V|FL_T|FL_Z))
	  | ((temp&0x80)  ? FL_N:0)
	  | ((temp&0x40)  ? FL_V:0)
	  | ((reg_a&temp) ? 0:FL_Z);
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void bit_zpx(void) {
  UChar temp = zpx_operand(reg_pc+1);
  reg_p = (reg_p & ~(FL_N|FL_V|FL_T|FL_Z))
	  | ((temp&0x80)  ? FL_N:0)
	  | ((temp&0x40)  ? FL_V:0)
	  | ((reg_a&temp) ? 0:FL_Z);
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void bmi(void) {
  reg_p &= ~FL_T;
  if (reg_p & FL_N) {
    reg_pc+=(Char)simm_operand(reg_pc+1)+2;
    cycles+=4;
  } else {
    reg_pc+=2;
    cycles+=2;
  }
//  return 0;
}

void bne(void) {
  reg_p &= ~FL_T;
  if (reg_p & FL_Z) {
    reg_pc+=2;
    cycles+=2;
  } else {
    reg_pc+=(Char)simm_operand(reg_pc+1)+2;
    cycles+=4;
  }
//  return 0;
}

void bpl(void) {
  reg_p &= ~FL_T;
  if (reg_p & FL_N) {
    reg_pc+=2;
    cycles+=2;
  } else {
    reg_pc+=(Char)simm_operand(reg_pc+1)+2;
    cycles+=4;
  }
//  return 0;
}

void bra(void) {
  reg_p &= ~FL_T;
  reg_pc+=(Char)simm_operand(reg_pc+1)+2;
  cycles+=4;
//  return 0;
}

void brek(void) {
#if defined(KERNEL_DEBUG)
  fprintf(stderr, "BRK opcode has been hit [PC = 0x%04x] at %s(%d)\n", reg_pc, __FILE__, __LINE__);
#endif
  push_16bit(reg_pc+2);
  reg_p &= ~FL_T;
  push_8bit(reg_p|FL_B);
  reg_p =(reg_p & ~FL_D) | FL_I;
  reg_pc=get_16bit_addr(0xFFF6);
  cycles+=8;
//  return 0;
}

void bsr(void) {
  reg_p &= ~FL_T;
  push_16bit(reg_pc+1);
  reg_pc+=(Char)simm_operand(reg_pc+1)+2;
  cycles+=8;
//  return 0;
}

void bvc(void) {
  reg_p &= ~FL_T;
  if (reg_p & FL_V) {
    reg_pc+=2;
    cycles+=2;
  } else {
    reg_pc+=(Char)simm_operand(reg_pc+1)+2;
    cycles+=4;
  }
//  return 0;
}

void bvs(void) {
  reg_p &= ~FL_T;
  if (reg_p & FL_V) {
    reg_pc+=(Char)simm_operand(reg_pc+1)+2;
    cycles+=4;
  } else {
    reg_pc+=2;
    cycles+=2;
  }
//  return 0;
}

void cla(void) {
  reg_p &= ~FL_T;
  reg_a = 0;
  reg_pc++;
  cycles+=2;
//  return 0;
}

void clc(void) {
  reg_p &= ~(FL_T|FL_C);
  reg_pc++;
  cycles+=2;
  return 0;
}

void cld(void) {
  reg_p &= ~(FL_T|FL_D);
  reg_pc++;
  cycles+=2;
//  return 0;
}

void cli(void) {
  reg_p &= ~(FL_T|FL_I);
  reg_pc++;
  cycles+=2;
//  return 0;
}

void clv(void) {
  reg_p &= ~(FL_V|FL_T);
  reg_pc++;
  cycles+=2;
//  return 0;
}

void clx(void) {
  reg_p &= ~FL_T;
  reg_x = 0;
  reg_pc++;
  cycles+=2;
//  return 0;
}

void cly(void) {
  reg_p &= ~FL_T;
  reg_y = 0;
  reg_pc++;
  cycles+=2;
//  return 0;
}

void cmp_abs(void) {
  UChar temp = abs_operand(reg_pc+1);

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((reg_a < temp) ? 0:FL_C)
	  | flnz_list[(UChar)(reg_a-temp)];
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void cmp_absx(void) {
  UChar temp = absx_operand(reg_pc+1);

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((reg_a < temp) ? 0:FL_C)
	  | flnz_list[(UChar)(reg_a-temp)];
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void cmp_absy(void) {
  UChar temp = absy_operand(reg_pc+1);

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((reg_a < temp) ? 0:FL_C)
	  | flnz_list[(UChar)(reg_a-temp)];
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void cmp_imm(void) {
  UChar temp = simm_operand(reg_pc+1);

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((reg_a < temp) ? 0:FL_C)
	  | flnz_list[(UChar)(reg_a-temp)];
  reg_pc+=2;
  cycles+=2;
//  return 0;
}

void cmp_zp(void) {
  UChar temp = zp_operand(reg_pc+1);

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((reg_a < temp) ? 0:FL_C)
	  | flnz_list[(UChar)(reg_a-temp)];
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void cmp_zpx(void) {
  UChar temp = zpx_operand(reg_pc+1);

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((reg_a < temp) ? 0:FL_C)
	  | flnz_list[(UChar)(reg_a-temp)];
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void cmp_zpind(void) {
  UChar temp = zpind_operand(reg_pc+1);

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((reg_a < temp) ? 0:FL_C)
	  | flnz_list[(UChar)(reg_a-temp)];
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void cmp_zpindx(void) {
  UChar temp = zpindx_operand(reg_pc+1);

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((reg_a < temp) ? 0:FL_C)
	  | flnz_list[(UChar)(reg_a-temp)];
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void cmp_zpindy(void) {
  UChar temp = zpindy_operand(reg_pc+1);

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((reg_a < temp) ? 0:FL_C)
	  | flnz_list[(UChar)(reg_a-temp)];
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void cpx_abs(void) {
  UChar temp = abs_operand(reg_pc+1);

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((reg_x < temp) ? 0:FL_C)
	  | flnz_list[(UChar)(reg_x-temp)];
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void cpx_imm(void) {
  UChar temp = simm_operand(reg_pc+1);

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((reg_x < temp) ? 0:FL_C)
	  | flnz_list[(UChar)(reg_x-temp)];
  reg_pc+=2;
  cycles+=2;
//  return 0;
}

void cpx_zp(void) {
  UChar temp = zp_operand(reg_pc+1);

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((reg_x < temp) ? 0:FL_C)
	  | flnz_list[(UChar)(reg_x-temp)];
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void cpy_abs(void) {
  UChar temp = abs_operand(reg_pc+1);

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((reg_y < temp) ? 0:FL_C)
	  | flnz_list[(UChar)(reg_y-temp)];
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void cpy_imm(void) {
  UChar temp = simm_operand(reg_pc+1);

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((reg_y < temp) ? 0:FL_C)
	  | flnz_list[(UChar)(reg_y-temp)];
  reg_pc+=2;
  cycles+=2;
//  return 0;
}

void cpy_zp(void) {
  UChar temp = zp_operand(reg_pc+1);

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((reg_y < temp) ? 0:FL_C)
	  | flnz_list[(UChar)(reg_y-temp)];
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void dec_a(void) {
  chk_flnz_8bit(--reg_a);
  reg_pc++;
  cycles+=2;
//  return 0;
}

void dec_abs(void) {
  UChar  temp;
  UInt16 temp_addr = get_16bit_addr(reg_pc+1);
  chk_flnz_8bit(temp = get_8bit_addr(temp_addr)-1);
  cycles+=7;
  put_8bit_addr(temp_addr, temp);
  reg_pc+=3;
//  return 0;
}

void dec_absx(void) {
  UChar  temp;
  UInt16 temp_addr = get_16bit_addr(reg_pc+1)+reg_x;
  chk_flnz_8bit(temp = get_8bit_addr(temp_addr)-1);
  cycles+=7;
  put_8bit_addr(temp_addr, temp);
  reg_pc+=3;
//  return 0;
}

void dec_zp(void) {
  UChar  temp;
  UChar  zp_addr = simm_operand(reg_pc+1);
  chk_flnz_8bit(temp = get_8bit_zp(zp_addr)-1);
  put_8bit_zp(zp_addr, temp);
  reg_pc+=2;
  cycles+=6;
//  return 0;
}

void dec_zpx(void) {
  UChar  temp;
  UChar  zp_addr = simm_operand(reg_pc+1)+reg_x;
  chk_flnz_8bit(temp = get_8bit_zp(zp_addr)-1);
  put_8bit_zp(zp_addr, temp);
  reg_pc+=2;
  cycles+=6;
//  return 0;
}

void dex(void) {
  chk_flnz_8bit(--reg_x);
  reg_pc++;
  cycles+=2;
//  return 0;
}

void dey(void) {
  chk_flnz_8bit(--reg_y);
  reg_pc++;
  cycles+=2;
//  return 0;
}

void eor_abs(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp ^= abs_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=8;

  } else {
    chk_flnz_8bit(reg_a ^= abs_operand(reg_pc+1));
    cycles+=5;
  }
  reg_pc+=3;
//  return 0;
}

void eor_absx(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp ^= absx_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=8;

  } else {
    chk_flnz_8bit(reg_a ^= absx_operand(reg_pc+1));
    cycles+=5;
  }
  reg_pc+=3;
//  return 0;
}

void eor_absy(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp ^= absy_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=8;

  } else {
    chk_flnz_8bit(reg_a ^= absy_operand(reg_pc+1));
    cycles+=5;
  }
  reg_pc+=3;
//  return 0;
}

void eor_imm(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp ^= simm_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=5;

  } else {
    chk_flnz_8bit(reg_a ^= simm_operand(reg_pc+1));
    cycles+=2;
  }
  reg_pc+=2;
//  return 0;
}

void eor_zp(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp ^= zp_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=7;

  } else {
    chk_flnz_8bit(reg_a ^= zp_operand(reg_pc+1));
    cycles+=4;
  }
  reg_pc+=2;
//  return 0;
}

void eor_zpx(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp ^= zpx_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=7;

  } else {
    chk_flnz_8bit(reg_a ^= zpx_operand(reg_pc+1));
    cycles+=4;
  }
  reg_pc+=2;
//  return 0;
}

void eor_zpind(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp ^= zpind_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=10;

  } else {
    chk_flnz_8bit(reg_a ^= zpind_operand(reg_pc+1));
    cycles+=7;
  }
  reg_pc+=2;
//  return 0;
}

void eor_zpindx(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp ^= zpindx_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=10;

  } else {
    chk_flnz_8bit(reg_a ^= zpindx_operand(reg_pc+1));
    cycles+=7;
  }
  reg_pc+=2;
//  return 0;
}

void eor_zpindy(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp ^= zpindy_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=10;

  } else {
    chk_flnz_8bit(reg_a ^= zpindy_operand(reg_pc+1));
    cycles+=7;
  }
  reg_pc+=2;
//  return 0;
}

void halt(void) {
 // return(1);
}

void inc_a(void) {
  chk_flnz_8bit(++reg_a);
  reg_pc++;
  cycles+=2;
//  return 0;
}

void inc_abs(void) {
  UChar  temp;
  UInt16 temp_addr = get_16bit_addr(reg_pc+1);
  chk_flnz_8bit(temp = get_8bit_addr(temp_addr)+1);
  cycles+=7;
  put_8bit_addr(temp_addr, temp);
  reg_pc+=3;
//  return 0;
}

void inc_absx(void) {
  UChar  temp;
  UInt16 temp_addr = get_16bit_addr(reg_pc+1)+reg_x;
  chk_flnz_8bit(temp = get_8bit_addr(temp_addr)+1);
  cycles+=7;
  put_8bit_addr(temp_addr, temp);
  reg_pc+=3;
//  return 0;
}

void inc_zp(void) {
  UChar temp;
  UChar zp_addr = simm_operand(reg_pc+1);
  chk_flnz_8bit(temp = get_8bit_zp(zp_addr)+1);
  put_8bit_zp(zp_addr, temp);

  reg_pc+=2;
  cycles+=6;
//  return 0;
}

void inc_zpx(void) {
  UChar temp;
  UChar zp_addr = simm_operand(reg_pc+1)+reg_x;
  chk_flnz_8bit(temp = get_8bit_zp(zp_addr)+1);
  put_8bit_zp(zp_addr, temp);
  reg_pc+=2;
  cycles+=6;
//  return 0;
}

void inx(void) {
  chk_flnz_8bit(++reg_x);
  reg_pc++;
  cycles+=2;
//  return 0;
}

void iny(void) {
  chk_flnz_8bit(++reg_y);
  reg_pc++;
  cycles+=2;
//  return 0;
}

void jmp(void) {
  reg_p &= ~FL_T;
  reg_pc = get_16bit_addr(reg_pc+1);
  cycles+=4;
//  return 0;
}

void jmp_absind(void) {
  reg_p &= ~FL_T;
  reg_pc = get_16bit_addr(get_16bit_addr(reg_pc+1));
  cycles+=7;
//  return 0;
}

void jmp_absindx(void) {
  reg_p &= ~FL_T;
  reg_pc = get_16bit_addr(get_16bit_addr(reg_pc+1)+reg_x);
  cycles+=7;
//  return 0;
}

void jsr(void) {
  reg_p &= ~FL_T;
  push_16bit(reg_pc+2);
  reg_pc = get_16bit_addr(reg_pc+1);
  cycles+=7;
//  return 0;
}

void lda_abs(void) {
  chk_flnz_8bit(reg_a = abs_operand(reg_pc+1));
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void lda_absx(void) {
  chk_flnz_8bit(reg_a = absx_operand(reg_pc+1));
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void lda_absy(void) {
  chk_flnz_8bit(reg_a = absy_operand(reg_pc+1));
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void lda_imm(void) {
  chk_flnz_8bit(reg_a = simm_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=2;
//  return 0;
}

void lda_zp(void) {
  chk_flnz_8bit(reg_a = zp_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void lda_zpx(void) {
  chk_flnz_8bit(reg_a = zpx_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void lda_zpind(void) {
  chk_flnz_8bit(reg_a = zpind_operand(reg_pc+1));

  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void lda_zpindx(void) {
  chk_flnz_8bit(reg_a = zpindx_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void lda_zpindy(void) {
  chk_flnz_8bit(reg_a = zpindy_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void ldx_abs(void) {
  chk_flnz_8bit(reg_x = abs_operand(reg_pc+1));
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void ldx_absy(void) {
  chk_flnz_8bit(reg_x = absy_operand(reg_pc+1));
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void ldx_imm(void) {
  chk_flnz_8bit(reg_x = simm_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=2;
//  return 0;
}

void ldx_zp(void) {
  chk_flnz_8bit(reg_x = zp_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void ldx_zpy(void) {
  chk_flnz_8bit(reg_x = zpy_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void ldy_abs(void) {
  chk_flnz_8bit(reg_y = abs_operand(reg_pc+1));
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void ldy_absx(void) {
  chk_flnz_8bit(reg_y = absx_operand(reg_pc+1));
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void ldy_imm(void) {
  chk_flnz_8bit(reg_y = simm_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=2;
//  return 0;
}

void ldy_zp(void) {
  chk_flnz_8bit(reg_y = zp_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void ldy_zpx(void) {
  chk_flnz_8bit(reg_y = zpx_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void lsr_a(void) {
  UChar temp = reg_a;
  reg_a/=2;
  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp&1) ? FL_C:0)
	  | flnz_list[reg_a];
  reg_pc++;
  cycles+=2;
//  return 0;
}

void lsr_abs(void) {
  UInt16 temp_addr = get_16bit_addr(reg_pc+1);
  UChar  temp1	   = get_8bit_addr(temp_addr);
  UChar  temp	   = temp1/2;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1&1) ? FL_C:0)
	  | flnz_list[temp];
  cycles+=7;
  put_8bit_addr(temp_addr, temp);
  reg_pc+=3;
//  return 0;
}

void lsr_absx(void) {
  UInt16 temp_addr = get_16bit_addr(reg_pc+1)+reg_x;
  UChar  temp1	   = get_8bit_addr(temp_addr);
  UChar  temp	   = temp1/2;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1&1) ? FL_C:0)
	  | flnz_list[temp];
  cycles+=7;
  put_8bit_addr(temp_addr, temp);
  reg_pc+=3;
//  return 0;
}

void lsr_zp(void) {
  UChar  zp_addr = simm_operand(reg_pc+1);
  UChar  temp1	 = get_8bit_zp(zp_addr);
  UChar  temp	 = temp1/2;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1&1) ? FL_C:0)
	  | flnz_list[temp];
  put_8bit_zp(zp_addr, temp);
  reg_pc+=2;
  cycles+=6;
//  return 0;
}

void lsr_zpx(void) {
  UChar  zp_addr = simm_operand(reg_pc+1)+reg_x;
  UChar  temp1	 = get_8bit_zp(zp_addr);
  UChar  temp	 = temp1/2;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1&1) ? FL_C:0)
	  | flnz_list[temp];
  put_8bit_zp(zp_addr, temp);
  reg_pc+=2;
  cycles+=6;
//  return 0;
}

void nop(void)  {
  reg_p &= ~FL_T;
  reg_pc++;
  cycles+=2;
//  return 0;
}

void ora_abs(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp |= abs_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=8;

  } else {
    chk_flnz_8bit(reg_a |= abs_operand(reg_pc+1));
    cycles+=5;
  }
  reg_pc+=3;
//  return 0;
}

void ora_absx(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp |= absx_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=8;

  } else {
    chk_flnz_8bit(reg_a |= absx_operand(reg_pc+1));
    cycles+=5;
  }
  reg_pc+=3;
//  return 0;
}

void ora_absy(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp |= absy_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=8;

  } else {
    chk_flnz_8bit(reg_a |= absy_operand(reg_pc+1));
    cycles+=5;
  }
  reg_pc+=3;
//  return 0;
}

void ora_imm(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp |= simm_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=5;

  } else {
    chk_flnz_8bit(reg_a |= simm_operand(reg_pc+1));
    cycles+=2;
  }
  reg_pc+=2;
//  return 0;
}

void ora_zp(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp |= zp_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=7;

  } else {
    chk_flnz_8bit(reg_a |= zp_operand(reg_pc+1));
    cycles+=4;
  }
  reg_pc+=2;
//  return 0;
}

void ora_zpx(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp |= zpx_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=7;

  } else {
    chk_flnz_8bit(reg_a |= zpx_operand(reg_pc+1));
    cycles+=4;
  }
  reg_pc+=2;
//  return 0;
}

void ora_zpind(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp |= zpind_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=10;

  } else {
    chk_flnz_8bit(reg_a |= zpind_operand(reg_pc+1));
    cycles+=7;
  }
  reg_pc+=2;
//  return 0;
}

void ora_zpindx(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp |= zpindx_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=10;

  } else {
    chk_flnz_8bit(reg_a |= zpindx_operand(reg_pc+1));
    cycles+=7;
  }
  reg_pc+=2;
//  return 0;
}

void ora_zpindy(void) {
  if (reg_p & FL_T) {
    UChar temp = get_8bit_zp(reg_x);
    chk_flnz_8bit(temp |= zpindy_operand(reg_pc+1));
    put_8bit_zp(reg_x, temp);
    cycles+=10;

  } else {
    chk_flnz_8bit(reg_a |= zpindy_operand(reg_pc+1));
    cycles+=7;
  }
  reg_pc+=2;
//  return 0;
}

void pha(void) {
  reg_p &= ~FL_T;
  push_8bit(reg_a);
  reg_pc++;
  cycles+=3;
//  return 0;
}

void php(void) {
  reg_p &= ~FL_T;
  push_8bit(reg_p);
  reg_pc++;
  cycles+=3;
//  return 0;
}

void phx(void) {
  reg_p &= ~FL_T;
  push_8bit(reg_x);
  reg_pc++;
  cycles+=3;
//  return 0;
}

void phy(void) {
  reg_p &= ~FL_T;
  push_8bit(reg_y);
  reg_pc++;
  cycles+=3;
//  return 0;
}

void pla(void) {
  chk_flnz_8bit(reg_a = pull_8bit());
  reg_pc++;
  cycles+=4;
//  return 0;
}

void plp(void) {
  reg_p = pull_8bit();
  reg_pc++;
  cycles+=4;
//  return 0;
}

void plx(void) {
  chk_flnz_8bit(reg_x = pull_8bit());
  reg_pc++;
  cycles+=4;
//  return 0;
}

void ply(void) {
  chk_flnz_8bit(reg_y = pull_8bit());
  reg_pc++;
  cycles+=4;
//  return 0;
}

void rmb0(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) & (~0x01));
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void rmb1(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) & (~0x02));
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void rmb2(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) & (~0x04));
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void rmb3(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) & (~0x08));
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void rmb4(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) & (~0x10));
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void rmb5(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) & (~0x20));
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void rmb6(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) & (~0x40));
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void rmb7(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) & (~0x80));
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void rol_a(void) {
  UChar flg_tmp = (reg_p & FL_C) ? 1:0;
  UChar temp = reg_a;

  reg_a = (reg_a<<1)+flg_tmp;
  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp & 0x80) ? FL_C:0)
	  | flnz_list[reg_a];
  reg_pc++;
  cycles+=2;
//  return 0;
}

void rol_abs(void) {
  UChar  flg_tmp   = (reg_p & FL_C) ? 1:0;
  UInt16 temp_addr = get_16bit_addr(reg_pc+1);
  UChar  temp1	   = get_8bit_addr(temp_addr);
  UChar  temp	   = (temp1<<1)+flg_tmp;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1 & 0x80) ? FL_C:0)
	  | flnz_list[temp];
  cycles+=7;
  put_8bit_addr(temp_addr, temp);
  reg_pc+=3;
//  return 0;
}

void rol_absx(void) {
  UChar  flg_tmp   = (reg_p & FL_C) ? 1:0;
  UInt16 temp_addr = get_16bit_addr(reg_pc+1)+reg_x;
  UChar  temp1	   = get_8bit_addr(temp_addr);
  UChar  temp	   = (temp1<<1)+flg_tmp;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1 & 0x80) ? FL_C:0)
	  | flnz_list[temp];
  cycles+=7;
  put_8bit_addr(temp_addr, temp);
  reg_pc+=3;
//  return 0;
}

void rol_zp(void) {
  UChar  flg_tmp = (reg_p & FL_C) ? 1:0;
  UChar  zp_addr = simm_operand(reg_pc+1);
  UChar  temp1	 = get_8bit_zp(zp_addr);
  UChar  temp	 = (temp1<<1)+flg_tmp;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1 & 0x80) ? FL_C:0)
	  | flnz_list[temp];
  put_8bit_zp(zp_addr, temp);
  reg_pc+=2;
  cycles+=6;
//  return 0;
}

void rol_zpx(void) {
  UChar  flg_tmp = (reg_p & FL_C) ? 1:0;
  UChar  zp_addr = simm_operand(reg_pc+1)+reg_x;
  UChar  temp1	 = get_8bit_zp(zp_addr);
  UChar  temp	 = (temp1<<1)+flg_tmp;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1 & 0x80) ? FL_C:0)
	  | flnz_list[temp];
  put_8bit_zp(zp_addr, temp);
  reg_pc+=2;
  cycles+=6;
//  return 0;
}

void ror_a(void) {
  UChar flg_tmp = (reg_p & FL_C) ? 0x80:0;
  UChar temp	= reg_a;

  reg_a = (reg_a/2)+flg_tmp;
  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp & 0x01) ? FL_C:0)
	  | flnz_list[reg_a];
  reg_pc++;
  cycles+=2;
//  return 0;
}

void ror_abs(void) {
  UChar  flg_tmp   = (reg_p & FL_C) ? 0x80:0;
  UInt16 temp_addr = get_16bit_addr(reg_pc+1);
  UChar  temp1	   = get_8bit_addr(temp_addr);
  UChar  temp	   = (temp1/2)+flg_tmp;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1 & 0x01) ? FL_C:0)
	  | flnz_list[temp];
  cycles+=7;
  put_8bit_addr(temp_addr, temp);
  reg_pc+=3;
//  return 0;
}

void ror_absx(void) {
  UChar  flg_tmp   = (reg_p & FL_C) ? 0x80:0;
  UInt16 temp_addr = get_16bit_addr(reg_pc+1)+reg_x;
  UChar  temp1	   = get_8bit_addr(temp_addr);
  UChar  temp	   = (temp1/2)+flg_tmp;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1 & 0x01) ? FL_C:0)
	  | flnz_list[temp];
  cycles+=7;
  put_8bit_addr(temp_addr, temp);
  reg_pc+=3;
//  return 0;
}

void ror_zp(void) {
  UChar  flg_tmp = (reg_p & FL_C) ? 0x80:0;
  UChar  zp_addr = simm_operand(reg_pc+1);
  UChar  temp1	 = get_8bit_zp(zp_addr);
  UChar  temp	 = (temp1/2)+flg_tmp;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1 & 0x01) ? FL_C:0)
	  | flnz_list[temp];
  put_8bit_zp(zp_addr, temp);
  reg_pc+=2;
  cycles+=6;
//  return 0;
}

void ror_zpx(void) {
  UChar  flg_tmp = (reg_p & FL_C) ? 0x80:0;
  UChar  zp_addr = simm_operand(reg_pc+1)+reg_x;
  UChar  temp1	 = get_8bit_zp(zp_addr);
  UChar  temp	 = (temp1/2)+flg_tmp;

  reg_p = (reg_p & ~(FL_N|FL_T|FL_Z|FL_C))
	  | ((temp1 & 0x01) ? FL_C:0)
	  | flnz_list[temp];
  put_8bit_zp(zp_addr, temp);
  reg_pc+=2;
  cycles+=6;
//  return 0;
}

void rti(void) {
  /* FL_B reset in RTI */
  reg_p = pull_8bit() & ~FL_B;
  reg_pc = pull_16bit();
  cycles+=7;
//  return 0;
}

void rts(void) {
  reg_p &= ~FL_T;
  reg_pc = pull_16bit()+1;
  cycles+=7;
//  return 0;
}

void sax(void) {
  UChar temp = reg_x;
  reg_p &= ~FL_T;
  reg_x = reg_a;
  reg_a = temp;
  reg_pc++;
  cycles+=3;
//  return 0;
}

void say(void) {
  UChar temp = reg_y;
  reg_p &= ~FL_T;
  reg_y = reg_a;
  reg_a = temp;
  reg_pc++;
  cycles+=3;
//  return 0;
}

void sbc_abs(void) {
  sbc(abs_operand(reg_pc+1));
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void sbc_absx(void) {
  sbc(absx_operand(reg_pc+1));
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void sbc_absy(void) {
  sbc(absy_operand(reg_pc+1));
  reg_pc+=3;
  cycles+=5;
//  return 0;
}

void sbc_imm(void) {
  sbc(simm_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=2;
//  return 0;
}

void sbc_zp(void) {
  sbc(zp_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void sbc_zpx(void) {
  sbc(zpx_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void sbc_zpind(void) {
  sbc(zpind_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void sbc_zpindx(void) {
  sbc(zpindx_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void sbc_zpindy(void) {
  sbc(zpindy_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void sec(void) {
  reg_p = (reg_p|FL_C) & ~FL_T;
  reg_pc++;
  cycles+=2;
//  return 0;
}

void sed(void) {
  reg_p = (reg_p|FL_D) & ~FL_T;
  reg_pc++;
  cycles+=2;
//  return 0;
}

void sei(void) {
#ifdef DUMP_ON_SEI
	void i;
	Log("MMR[7]\n");
	for (i = 0xE000; i < 0xE100; i++)
		{
			Log("%02X ", get_8bit_addr(i));
		}
#endif
  reg_p = (reg_p|FL_I) & ~FL_T;
  reg_pc++;
  cycles+=2;
//  return 0;
}

void set(void) {
  reg_p |= FL_T;
  reg_pc++;
  cycles+=2;
//  return 0;
}

void smb0(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) | 0x01);
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void smb1(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) | 0x02);
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void smb2(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) | 0x04);
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void smb3(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) | 0x08);
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void smb4(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) | 0x10);
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void smb5(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) | 0x20);
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void smb6(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) | 0x40);
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void smb7(void) {
  UChar temp = simm_operand(reg_pc+1);
  reg_p &= ~FL_T;
  put_8bit_zp(temp, get_8bit_zp(temp) | 0x80);
  reg_pc+=2;
  cycles+=7;
//  return 0;
}

void st0(void) {
  reg_p &= ~FL_T;
  IO_write(0,simm_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void st1(void) {
  reg_p &= ~FL_T;
  IO_write(2,simm_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void st2(void) {
  reg_p &= ~FL_T;
  IO_write(3,simm_operand(reg_pc+1));
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void sta_abs(void) {
  reg_p &= ~FL_T;
  cycles+=5;
  put_8bit_addr(get_16bit_addr(reg_pc+1), reg_a);
  reg_pc+=3;
//  return 0;
}

void sta_absx(void) {
  reg_p &= ~FL_T;
  cycles+=5;
  put_8bit_addr(get_16bit_addr(reg_pc+1)+reg_x, reg_a);
  reg_pc+=3;
//  return 0;
}

void sta_absy(void) {
  reg_p &= ~FL_T;
  cycles+=5;
  put_8bit_addr(get_16bit_addr(reg_pc+1)+reg_y, reg_a);
  reg_pc+=3;
//  return 0;
}

void sta_zp(void) {
  reg_p &= ~FL_T;
  put_8bit_zp(simm_operand(reg_pc+1), reg_a);

  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void sta_zpx(void) {
  reg_p &= ~FL_T;
  put_8bit_zp(simm_operand(reg_pc+1)+reg_x, reg_a);
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void sta_zpind(void) {
  reg_p &= ~FL_T;
  cycles+=7;
  put_8bit_addr(get_16bit_zp(simm_operand(reg_pc+1)), reg_a);
  reg_pc+=2;
//  return 0;
}

void sta_zpindx(void) {
  reg_p &= ~FL_T;
  cycles+=7;
  put_8bit_addr(get_16bit_zp(simm_operand(reg_pc+1)+reg_x), reg_a);
  reg_pc+=2;
//  return 0;
}

void sta_zpindy(void) {
  reg_p &= ~FL_T;
  cycles+=7;
  put_8bit_addr(get_16bit_zp(simm_operand(reg_pc+1))+reg_y, reg_a);
  reg_pc+=2;
//  return 0;
}

void stx_abs(void) {
  reg_p &= ~FL_T;
  cycles+=5;
  put_8bit_addr(get_16bit_addr(reg_pc+1), reg_x);
  reg_pc+=3;
//  return 0;
}

void stx_zp(void) {
  reg_p &= ~FL_T;
  put_8bit_zp(simm_operand(reg_pc+1), reg_x);
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void stx_zpy(void) {
  reg_p &= ~FL_T;
  put_8bit_zp(simm_operand(reg_pc+1)+reg_y, reg_x);
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void sty_abs(void) {
  reg_p &= ~FL_T;
  cycles+=5;
  put_8bit_addr(get_16bit_addr(reg_pc+1), reg_y);
  reg_pc+=3;
//  return 0;
}

void sty_zp(void) {
  reg_p &= ~FL_T;
  put_8bit_zp(simm_operand(reg_pc+1), reg_y);
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void sty_zpx(void) {
  reg_p &= ~FL_T;
  put_8bit_zp(simm_operand(reg_pc+1)+reg_x, reg_y);
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void stz_abs(void) {
  reg_p &= ~FL_T;
  cycles+=5;
  put_8bit_addr(get_16bit_addr(reg_pc+1), 0);
  reg_pc+=3;
//  return 0;
}

void stz_absx(void) {
  reg_p &= ~FL_T;
  cycles+=5;
  put_8bit_addr((get_16bit_addr(reg_pc+1)+reg_x), 0);
  reg_pc+=3;
//  return 0;
}

void stz_zp(void) {
  reg_p &= ~FL_T;
  put_8bit_zp(simm_operand(reg_pc+1), 0);
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void stz_zpx(void) {
  reg_p &= ~FL_T;
  put_8bit_zp(simm_operand(reg_pc+1)+reg_x, 0);
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void sxy(void) {
  UChar temp = reg_y;
  reg_p &= ~FL_T;
  reg_y = reg_x;
  reg_x = temp;
  reg_pc++;
  cycles+=3;
//  return 0;
}

void tai(void) {
  UInt16 from, to, len, alternate;

  reg_p &= ~FL_T;
  from = get_16bit_addr(reg_pc+1);
  to   = get_16bit_addr(reg_pc+3);
  len  = get_16bit_addr(reg_pc+5);
  alternate = 0;

#if defined(CD_DEBUG) && defined(INLINED_ACCESSORS)
  fprintf(stderr, "Transfert from bank 0x%02x to bank 0x%02x\n", mmr[from >> 13], mmr[to >> 13]);
#endif

  cycles+=(6 * len) + 17;
  while (len-- != 0) {
    put_8bit_addr(to++, get_8bit_addr(from+alternate));
    alternate ^= 1;
  }
  reg_pc+=7;
//  return 0;
}

void tam(void) {
  UInt16 i;
  UChar bitfld = simm_operand(reg_pc+1);

#if defined(KERNEL_DEBUG)
  if (bitfld == 0)
    {
      fprintf(stderr, "TAM with argument 0\n");
      Log("TAM with argument 0\n");
    }
  else if (!one_bit_set(bitfld))
    {
      fprintf(stderr, "TAM with unusual argument 0x%02x\n", bitfld);
      Log("TAM with unusual argument 0x%02x\n", bitfld);
    }
#endif

  for (i = 0; i < 8; i++) {
    if (bitfld & (1 << i)) {
      mmr[i] = reg_a;
      bank_set(i, reg_a);
    }
  }

  reg_p &= ~FL_T;
  reg_pc+=2;
  cycles+=5;
//  return 0;
}

void tax(void) {
  chk_flnz_8bit(reg_x = reg_a);
  reg_pc++;
  cycles+=2;
//  return 0;
}

void tay(void) {
  chk_flnz_8bit(reg_y = reg_a);
  reg_pc++;
  cycles+=2;
//  return 0;
}

void tdd(void) {
  UInt16 from, to, len;

  reg_p &= ~FL_T;
  from = get_16bit_addr(reg_pc+1);
  to   = get_16bit_addr(reg_pc+3);
  len  = get_16bit_addr(reg_pc+5);

#if defined(CD_DEBUG) && defined(INLINED_ACCESSORS)
  fprintf(stderr, "Transfert from bank 0x%02x to bank 0x%02x\n", mmr[from >> 13], mmr[to >> 13]);
#endif

  cycles+=(6 * len) + 17;
  while (len-- != 0) {
    put_8bit_addr(to--, get_8bit_addr(from--));
  }
  reg_pc+=7;
//  return 0;
}

void tia(void) {
  UInt16 from, to, len, alternate;

  reg_p &= ~FL_T;
  from = get_16bit_addr(reg_pc+1);
  to   = get_16bit_addr(reg_pc+3);
  len  = get_16bit_addr(reg_pc+5);
  alternate = 0;

#if defined(CD_DEBUG) && defined(INLINED_ACCESSORS)
  fprintf(stderr, "Transfert from bank 0x%02x to bank 0x%02x\n", mmr[from >> 13], mmr[to >> 13]);
#endif

  cycles+=(6 * len) + 17;
  while (len-- != 0) {
    put_8bit_addr(to+alternate, get_8bit_addr(from++));
    alternate ^= 1;
  }
  reg_pc+=7;
//  return 0;
}

void tii(void) {
  UInt16 from, to, len;

  reg_p &= ~FL_T;
  from = get_16bit_addr(reg_pc+1);
  to   = get_16bit_addr(reg_pc+3);
  len  = get_16bit_addr(reg_pc+5);

#if defined(CD_DEBUG) && defined(INLINED_ACCESSORS)
  fprintf(stderr, "Transfert from bank 0x%02x to bank 0x%02x\n", mmr[from >> 13], mmr[to >> 13]);
#endif

  cycles+=(6 * len) + 17;
  while (len-- != 0) {
    put_8bit_addr(to++, get_8bit_addr(from++));
  }
  reg_pc+=7;
//  return 0;
}

void tin(void) {
  UInt16 from, to, len;

  reg_p &= ~FL_T;
  from = get_16bit_addr(reg_pc+1);
  to   = get_16bit_addr(reg_pc+3);
  len  = get_16bit_addr(reg_pc+5);

#if defined(CD_DEBUG) && defined(INLINED_ACCESSORS)
  fprintf(stderr, "Transfert from bank 0x%02x to bank 0x%02x\n", mmr[from >> 13], mmr[to >> 13]);
#endif

  cycles+=(6 * len) + 17;
  while (len-- != 0) {
    put_8bit_addr(to, get_8bit_addr(from++));
  }
  reg_pc+=7;
//  return 0;
}

void tma(void) {
  int i;
  UChar bitfld = simm_operand(reg_pc+1);

#if defined(KERNEL_DEBUG)
  if (bitfld == 0)
    {
      fprintf(stderr, "TMA with argument 0\n");
      Log("TMA with argument 0\n");
    }
  else if (!one_bit_set(bitfld))
    {
      fprintf(stderr, "TMA with unusual argument 0x%02x\n", bitfld);
      Log("TMA with unusual argument 0x%02x\n", bitfld);
    }
#endif

  for (i = 0; i < 8; i++) {
    if (bitfld & (1 << i)) {
      reg_a = mmr[i];
    }
  }
  reg_p &= ~FL_T;
  reg_pc+=2;
  cycles+=4;
//  return 0;
}

void trb_abs(void) {
  UInt16 abs_addr = get_16bit_addr(reg_pc+1);
  UChar  temp	  = get_8bit_addr(abs_addr);
  UChar  temp1	  = (~reg_a) & temp;

  reg_p = (reg_p & ~(FL_N|FL_V|FL_T|FL_Z))
	  | ((temp1&0x80) ? FL_N:0)
	  | ((temp1&0x40) ? FL_V:0)
	  | ((temp & reg_a) ? 0:FL_Z);
  cycles+=7;
  put_8bit_addr(abs_addr, temp1);
  reg_pc+=3;
//  return 0;
}

void trb_zp(void) {
  UChar zp_addr  = simm_operand(reg_pc+1);
  UChar temp	 = get_8bit_zp(zp_addr);
  UChar temp1	 = (~reg_a) & temp;

  reg_p = (reg_p & ~(FL_N|FL_V|FL_T|FL_Z))
	  | ((temp1&0x80) ? FL_N:0)
	  | ((temp1&0x40) ? FL_V:0)
	  | ((temp & reg_a) ? 0:FL_Z);
  put_8bit_zp(zp_addr, temp1);
  reg_pc+=2;
  cycles+=6;
//  return 0;
}

void tsb_abs(void) {
  UInt16 abs_addr = get_16bit_addr(reg_pc+1);
  UChar  temp	  = get_8bit_addr(abs_addr);
  UChar  temp1	  = reg_a | temp;

  reg_p = (reg_p & ~(FL_N|FL_V|FL_T|FL_Z))
	  | ((temp1&0x80) ? FL_N:0)
	  | ((temp1&0x40) ? FL_V:0)
	  | ((temp & reg_a) ? 0:FL_Z);
  cycles+=7;
  put_8bit_addr(abs_addr, temp1);
  reg_pc+=3;
//  return 0;
}

void tsb_zp(void) {
  UChar zp_addr  = simm_operand(reg_pc+1);
  UChar temp	 = get_8bit_zp(zp_addr);
  UChar temp1	 = reg_a | temp;

  reg_p = (reg_p & ~(FL_N|FL_V|FL_T|FL_Z))
	  | ((temp1&0x80) ? FL_N:0)
	  | ((temp1&0x40) ? FL_V:0)
	  | ((temp & reg_a) ? 0:FL_Z);
  put_8bit_zp(zp_addr, temp1);
  reg_pc+=2;
  cycles+=6;
//  return 0;
}

void tstins_abs(void) {
  UChar  imm	  = simm_operand(reg_pc+1);
  UChar  temp	  = abs_operand(reg_pc+2);

  reg_p = (reg_p & ~(FL_N|FL_V|FL_T|FL_Z))
	  | ((temp&0x80) ? FL_N:0)
	  | ((temp&0x40) ? FL_V:0)
	  | ((temp&imm)  ? 0:FL_Z);
  cycles+=8;
  reg_pc+=4;
//  return 0;
}

void tstins_absx(void) {
  UChar  imm	  = simm_operand(reg_pc+1);
  UChar  temp	  = absx_operand(reg_pc+2);

  reg_p = (reg_p & ~(FL_N|FL_V|FL_T|FL_Z))
	  | ((temp&0x80) ? FL_N:0)
	  | ((temp&0x40) ? FL_V:0)
	  | ((temp&imm)  ? 0:FL_Z);
  cycles+=8;
  reg_pc+=4;
//  return 0;
}

void tstins_zp(void) {
  UChar imm	= simm_operand(reg_pc+1);
  UChar temp	= zp_operand(reg_pc+2);

  reg_p = (reg_p & ~(FL_N|FL_V|FL_T|FL_Z))
	  | ((temp&0x80) ? FL_N:0)
	  | ((temp&0x40) ? FL_V:0)
	  | ((temp&imm)  ? 0:FL_Z);
  cycles+=7;
  reg_pc+=3;
//  return 0;
}

void tstins_zpx(void) {
  UChar imm	= simm_operand(reg_pc+1);
  UChar temp	= zpx_operand(reg_pc+2);

  reg_p = (reg_p & ~(FL_N|FL_V|FL_T|FL_Z))
	  | ((temp&0x80) ? FL_N:0)
	  | ((temp&0x40) ? FL_V:0)
	  | ((temp&imm)  ? 0:FL_Z);
  cycles+=7;
  reg_pc+=3;
//  return 0;
}


void tsx(void) {
  chk_flnz_8bit(reg_x = reg_s);
  reg_pc++;
  cycles+=2;
//  return 0;
}

void txa(void) {
  chk_flnz_8bit(reg_a = reg_x);
  reg_pc++;
  cycles+=2;
//  return 0;
}

void txs(void) {
  reg_p &= ~FL_T;
  reg_s = reg_x;
  reg_pc++;
  cycles+=2;
//  return 0;
}

void tya(void) {
  chk_flnz_8bit(reg_a = reg_y);
  reg_pc++;
  cycles+=2;
//  return 0;
}

// perform machine operations for IRQ2:

void int_irq2 (void) {
  if ((io.irq_mask & FL_IRQ2) != 0) {   // interrupt disabled
     return 0;
  }
//if ((irq_register & FL_IRQ2) == 0) {	 // interrupt disabled ?
// //  return 0;
//}
  cycles+=7;
  push_16bit(reg_pc);
  push_8bit(reg_p);
  reg_p = (reg_p & ~FL_D) | FL_I;
  reg_pc = get_16bit_addr(0xFFF6);
//  return 0;
}

// perform machine operations for IRQ1 (video interrupt):

void int_irq1 (void) {
  if ((io.irq_mask & FL_IRQ1) != 0) {   // interrupt disabled
     return 0;
  }
//if ((irq_register & FL_IRQ1) == 0) {	 // interrupt disabled ?
//   return 0;
//}
  cycles+=7;
  push_16bit(reg_pc);
  push_8bit(reg_p);
  reg_p = (reg_p & ~FL_D) | FL_I;
  reg_pc = get_16bit_addr(0xFFF8);
//  return 0;
}

// perform machine operations for timer interrupt:

void int_tiq(void) {
  if ((io.irq_mask & FL_TIQ) != 0) {    // interrupt disabled
     return 0;
  }
//if ((irq_register & FL_TIQ) == 0) {	// interrupt disabled ?
//   return 0;
//}
  cycles+=7;
  push_16bit(reg_pc);
  push_8bit(reg_p);
  reg_p = (reg_p & ~FL_D) | FL_I;
  reg_pc = get_16bit_addr(0xFFFA);
//  return 0;
}

/*@ =type */

// Execute a single instruction :

void exe_instruct(void) {
  (*optable_runtime[PageR[reg_pc>>13][reg_pc]].func_exe)();
}

static void
Int6502 (UChar Type)
{
  UInt16 J;

  if ((Type == INT_NMI) || (!(reg_p & FL_I)))
    {
      cycles += 7;
      push_16bit(reg_pc);
      push_8bit(reg_p);
      reg_p = (reg_p & ~FL_D);
/*
      WrRAM (SP + R->S,
	     ((R->P & ~(B_FLAG | T_FLAG)) & ~(N_FLAG | V_FLAG | Z_FLAG)) |
	     (R->NF & N_FLAG) | (R->VF & V_FLAG) | (R->ZF ? 0 : Z_FLAG));
*/

      if (Type == INT_NMI)
	{
	  J = VEC_NMI;
	}
      else
	{
          reg_p |=  FL_I;

	  switch (Type)
	    {

	    case INT_IRQ:
	      J = VEC_IRQ;
	      break;

	    case INT_IRQ2:
	      J = VEC_IRQ2;
	      break;

	    case INT_TIMER:
	      J = VEC_TIMER;
	      break;

	    }

	}
#ifdef KERNEL_DEBUG
			Log("Interruption : %04X\n", J);
#endif
      reg_pc = get_16bit_addr((UInt16)J);
    } else {
#ifdef KERNEL_DEBUG
    	Log("Dropped interruption %02X\n", Type);
#endif
    }
}

//! Log all needed info to guess what went wrong in the cpu
void dump_pce_core() {

  int i;

  fprintf(stderr, "Dumping PCE core\n");

  Log("PC = 0x%04x\n", reg_pc);
  Log("A = 0x%02x\n", reg_a);
  Log("X = 0x%02x\n", reg_x);
  Log("Y = 0x%02x\n", reg_y);
  Log("P = 0x%02x\n", reg_p);
  Log("S = 0x%02x\n", reg_s);

  for (i = 0; i < 8; i++)
    {
      Log("MMR[%d] = 0x%02x\n", i, mmr[i]);
    }

  for (i = 0x2000; i < 0xFFFF; i++)
    {

      if ((i & 0xF) == 0)
        {
          Log("%04X: ", i);
        }

      Log("%02x ", get_8bit_addr((UInt16)i));
      if ((i & 0xF) == 0xF)
        {
          Log("\n");
        }
      if ((i & 0x1FFF) == 0x1FFF)
        {
          Log("\n-------------------------------------------------------------\n");
        }
    }

}


#ifdef BENCHMARK
/* code copied from utils.c */
#include <sys/time.h>
static double osd_getTime(void)
{
#ifdef WIN32  
  return (SDL_GetTicks() * 1e-3);
#elif defined(DJGPP)
  return uclock() * (1.0 / UCLOCKS_PER_SEC);
#else
  struct timeval tp;

  gettimeofday(&tp, NULL);
  // printf("current microsec = %f\n",tp.tv_sec + 1e-6 * tp.tv_usec);
  return tp.tv_sec + 1e-6 * tp.tv_usec;
#endif
}
#endif

void (*optable_temp[315])(void) = {
	brek,		ora_zpindx,	sxy,		st0,		tsb_zp,		ora_zp,  
	asl_zp,		rmb0,		php,		ora_imm,	asl_a,		handle_bp0,
	tsb_abs,	ora_abs,	asl_abs,	bbr0,		bpl,		ora_zpindy,
	ora_zpind,	st1, 		trb_zp,		ora_zpx,	asl_zpx,	rmb1, 
	clc,		ora_absy,	inc_a,		handle_bp1,	trb_abs,	ora_absx,
	asl_absx,	bbr1,		jsr,		and_zpindx,	sax,		st2,
	bit_zp,		and_zp,		rol_zp,		rmb2,		plp,		and_imm,
	rol_a,		handle_bp2,	bit_abs,	and_abs,	rol_abs,	bbr2,
	bmi,		and_zpindy,	and_zpind,	halt,		bit_zpx,	and_zpx,
	rol_zpx,	rmb3,		sec,		and_absy,	dec_a,		handle_bp3,
	bit_absx,	and_absx,	rol_absx,	bbr3,		rti,		eor_zpindx,
	say,		tma,		bsr,		eor_zp,		lsr_zp,		rmb4,
	pha,		eor_imm,	lsr_a,		handle_bp4,	jmp,		eor_abs,
	lsr_abs,	bbr4,		bvc,		eor_zpindy,	eor_zpind,	tam,
  	nop,		eor_zpx,	lsr_zpx,	rmb5,		cli,		eor_absy,
	phy,		handle_bp5,	halt,		eor_absx,	lsr_absx,	bbr5,
	rts,		adc_zpindx, cla,		halt,		stz_zp,		adc_zp,
	ror_zp,		rmb6,		pla,		adc_imm,	ror_a,		handle_bp6,
	jmp_absind,	adc_abs,	ror_abs,	bbr6,bvs,	adc_zpindy,	adc_zpind,tii,
	stz_zpx,	adc_zpx,	ror_zpx,	rmb7,		sei,		adc_absy,
	ply,		handle_bp7,	jmp_absindx,adc_absx,	ror_absx,	bbr7, 
	bra,		sta_zpindx,	clx,		tstins_zp,	sty_zp,		sta_zp,
	stx_zp,		smb0,		dey,		bit_imm,	txa,		handle_bp8,
	sty_abs,	sta_abs,	stx_abs,	bbs0,		bcc,		sta_zpindy,
	sta_zpind,	tstins_abs,	sty_zpx,	sta_zpx,	stx_zpy,	smb1,
	tya,		sta_absy,	txs,		handle_bp9,	stz_abs,	sta_absx, 
	stz_absx,	bbs1,		ldy_imm,	lda_zpindx,	ldx_imm,	tstins_zpx,
	ldy_zp,		lda_zp, 	ldx_zp,		smb2,tay,	lda_imm,	tax,
	handle_bp10,ldy_abs,	lda_abs,	ldx_abs,	bbs2,		bcs,
	lda_zpindy,	lda_zpind,	tstins_absx,ldy_zpx,	lda_zpx,	ldx_zpy,
	smb3,		clv,		lda_absy,	tsx, 		handle_bp11,ldy_absx,
	lda_absx,	ldx_absy,	bbs3,		cpy_imm,	cmp_zpindx,	cly,
	tdd,		cpy_zp,		cmp_zp,		dec_zp,		smb4,		iny,
	cmp_imm,	dex,		handle_bp12,cpy_abs,	cmp_abs,	dec_abs,
	bbs4,		bne,		cmp_zpindy,	cmp_zpind,	tin,		nop,
	cmp_zpx,	dec_zpx,	smb5,		cld,		cmp_absy,	phx,
	handle_bp13,halt,		cmp_absx,	dec_absx,	bbs5,		cpx_imm,
	sbc_zpindx,	halt,		tia,		cpx_zp,		sbc_zp,		inc_zp,
	smb6,		inx,		sbc_imm,	nop,		handle_bp14,cpx_abs,
	sbc_abs,	inc_abs,	bbs6,		beq,		sbc_zpindy,	sbc_zpind, 
	tai,		set,		sbc_zpx,	inc_zpx, 	smb7,		sed,
	sbc_absy,	plx,		handle_bp15,handle_bios,sbc_absx,	inc_absx,
	bbs7
};

// Execute instructions as a machine would, including all
// important (known) interrupts, hardware functions, and
// actual video display on the hardware
//
// Until the following happens:
// (1) An unknown instruction is to be executed
// (2) An unknown hardware access is performed
// (3) <ESC> key is hit

void exe_go(void) {
  int err = 0;
  UChar I;

#if defined(KERNEL_DEBUG)
  UInt16 old_reg_pc;
#endif

#ifdef BENCHMARK
  static int countNb = 8;   /* run for 8 * 65536 scan lines */
  static int countScan = 0; /* scan line counter */
  static double lastTime;
  lastTime = osd_getTime();
#endif

  // err is set on a 'trap':
//  while (!err) {
    for(;;) {



#ifdef DEBUG_KERNEL_DS

#endif


#if defined(SHARED_MEMORY)
 //   if (external_control_cpu >= 0) {
 //     while (external_control_cpu == 0) {
#if defined(WIN32)
//        SDL_Delay(1);
#else
//        usleep(1);
#endif
 //     }
 //     if (external_control_cpu > 0)
 //       external_control_cpu--;
 //   }
#endif

#if defined(KERNEL_DEBUG)
    old_reg_pc = reg_pc;
#endif

#undef OPCODE_LOGGING
#if defined(OPCODE_LOGGING)
#if defined(SDL)
//    extern Uint8* key;

	// if (!key[SDLK_F11])
#endif
	if (0xC7A8 == reg_pc) {
		UChar offset = PageR[reg_pc >> 13][reg_pc + 1];
//		Log("C7A8 !! %02X\n", offset);
//		Log("zp[%02X] = %02X\n", offset, get_8bit_addr(get_16bit_zp(offset)));
	}
//    Log("[%04X] (%02X) (%02X,%02X,%02X) (%02X,%02X) {%02X,%04X} {%02X}\n",
        reg_pc,
        PageR[reg_pc>>13][reg_pc],
        reg_a,
        reg_x,
        reg_y,
        reg_s,
        reg_p,
        get_8bit_addr(get_16bit_zp(0)),
        get_16bit_zp(0),
        get_8bit_zp(0x48));
#endif

#ifdef USE_INSTR_SWITCH
#include "instr-switch.c"
#else
 //   err = (*optable_runtime[PageR[reg_pc>>13][reg_pc]].func_exe)();
//			(*optable_runtime[PageR[reg_pc>>13][reg_pc]].func_exe)();
			optable_temp[PageR[reg_pc>>13][reg_pc]]();
#endif

#if defined(KERNEL_DEBUG)

    if (mmr[2] == 0x69)
      {
        static int old_4062 = -1;
        if (PageR[0x4062 >> 13][0x4062] != old_4062)
          {
    //        Log("[0x4062] changed from 0x%02x to 0x%02x\n", old_4062, PageR[0x4062 >> 13][0x4062]);
            old_4062 = PageR[0x4062 >> 13][0x4062];
          }
      }

    if (reg_pc < 0x2000)
      {
 //       fprintf(stderr, "PC in I/O area [0x%04x] referer = 0x%04x\n", reg_pc, old_reg_pc);
 //       Log("PC in I/O area [0x%04x] referer = 0x%04x\n", reg_pc, old_reg_pc);
      }

//    if (err)
//      {
//        dump_pce_core();

//      }
#endif


    // HSYNC stuff - count cycles:
    if (cycles > 455)
      {

#ifdef BENCHMARK
        countScan++;
        if ((countScan & 0xFFFF) == 0) {
          double currentTime = osd_getTime();
          printf("%f\n", currentTime - lastTime);
          lastTime = currentTime;
          countNb--;
          if (countNb == 0) return;
        }
#endif

        CycleNew += cycles;
        cycles -= 455;

        I = Loop6502 ();	/* Call the periodic handler */

        /* Reset the cycle counter */
        cycles = 0;

/*        if (I == INT_QUIT)
          {
#if !defined(FINAL_RELEASE)
            fprintf(stderr,"Normal exit of the cpu loop (INT_QUIT interruption caught)\n");
#endif
            return;	// Exit if INT_QUIT    
          }*/
        if (I)
          Int6502 (I);	/* Interrupt if needed  */

        if ((unsigned int) (CycleNew - cyclecountold) >
            (unsigned int) TimerPeriod * 2)

          cyclecountold = CycleNew;

      }
    else
      {

        if (CycleNew - cyclecountold >= TimerPeriod)
          {
            cyclecountold += TimerPeriod;
            I = TimerInt ();
            if (I)
              Int6502 (I);
          }

      }

  }
#if !defined(FINAL_RELEASE)
  fprintf(stderr,"Abnormal exit from the cpu loop\n");
#endif
  Log("Abnormal exit from the cpu loop\n");
}
